//
//  IvcsAgent.m
//  IVCS
//
//  Created by nfl on 2022/2/28.
//  Copyright © 2022 zco user. All rights reserved.
//

#import "IvcsAgent.h"
#import <IVCS/IVCS.h>
#import <IVCS/Constant.h>
#import <IVCS/IRTCSDK.h>
#import <IVCS/CCSClient.h>
#import "IvcsAgentDelegate.h"
#import "AgentCcsClientMessageDelegate.h"
#import "AgentApi.h"
#import "AmsClient.h"

static NSString *ivcsAgentSDKErrorDomain = @"company.ivcs.agent.sdk";

@interface IvcsAgent()<IRTCSDKDelegate>
/// 保存用户的登录信息
@property(strong , nonatomic)ZcoModelUserInfo *zcoModelUserInfo;

/// ccs socketIo client
@property(strong,nonatomic)CCSClient *ccsClient;

/// irtc sdk
@property(strong,nonatomic)IRTCSDK *irtcSDK;

/// default webrtc stream setting parameter
@property(strong,nonatomic)MediaStreamSettingOptions *mediaOptions;

@property(strong , nonatomic)ZcoModelSessionInfo *sessionInfo;
/// zms roomn token
@property(copy,nonatomic)NSString *roomToken;

@property(copy , nonatomic)NSString *roomId ;

@property(copy , nonatomic)NSString *sessionId ;

@property(copy , nonatomic)NSString *clientId ;

@property(copy , nonatomic)NSString *baseUrl;

@property(strong , nonatomic)NSMutableDictionary *labelAndStreams;

@property(copy , nonatomic)NSString *localStreamLabel ;

@property(strong, nonatomic) IRTCLocalCameraStream *localStream;
@property(nonatomic, strong) NSArray<IRTCRemoteStream*>* remoteStreams;

@end

@implementation IvcsAgent

relizeSingleInstance(Agent)

// 当没有传递要发送的角色时，默认传 customer
NSString* (^ agentCheckRole)(NSString *) = ^(NSString* role){
    return role == nil ? @"customers" : role;
};

-(NSMutableDictionary *)labelAndStreams{
    _labelAndStreams = self.irtcSDK.labelAndStreams;
    return _labelAndStreams;
}

-(void)initWithServiceUrl:(NSString *)serviceUrl name:(NSString *)name password:(NSString *)password org:(NSString *)org mediaOptions:(MediaStreamSettingOptions *)mediaOptions onSuccess:(void (^)(ZcoModelUserInfo * _Nonnull))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
       //数据校验
       if (serviceUrl == nil || name == nil || password == nil || org == nil) {
           NSError *error = [[NSError alloc] initWithDomain:ivcsAgentSDKErrorDomain code:105 userInfo:@{@"reason":@"请检查 url地址 登录名 密码 机构名 是否为空"}];
           onFailure(error);
           return;
       }
       //设置音视频参数，nil则使用默认的音视频参数
       if (mediaOptions == nil) {
           self.mediaOptions = [[MediaStreamSettingOptions alloc] init];
           IRTCStreamConstraints *constraints = [[IRTCStreamConstraints alloc] init];
           constraints.audio = true;
           constraints.video=[[IRTCVideoTrackConstraints alloc] init];
           constraints.video.frameRate = 15;
           constraints.video.resolution = CGSizeMake(640,480);
           constraints.video.devicePosition = AVCaptureDevicePositionFront;
           self.mediaOptions.streamConstraints = constraints;
           IRTCPublishOptions* options=[[IRTCPublishOptions alloc] init];
           IRTCVideoCodecParameters *h264Parameters=[[IRTCVideoCodecParameters alloc] init];
           h264Parameters.name=IRTCVideoCodecH264;
           IRTCVideoEncodingParameters *videoParameters=[[IRTCVideoEncodingParameters alloc]init];
           videoParameters.codec=h264Parameters;
           videoParameters.maxBitrate = 512;
           options.video=[NSArray arrayWithObjects:videoParameters, nil];
           IRTCAudioCodecParameters* pcmuParameters=[[IRTCAudioCodecParameters alloc] init];
           pcmuParameters.name=IRTCAudioCodecPcmu;
           IRTCAudioEncodingParameters *audioParameters=[[IRTCAudioEncodingParameters alloc] init];
           audioParameters.codec=pcmuParameters;
           options.audio=[NSArray arrayWithObjects:audioParameters, nil];
           self.mediaOptions.publishOptions = options;
       }else{
           self.mediaOptions = [mediaOptions copy];
       }
       AgentApi *api = [AgentApi sharedAgent];
       [api loginWithUrl:serviceUrl name:name password:password
                     org:org complete:^(CallBackObject * _Nonnull result) {
           if (result.code == 200) {
               // 登录成功后初始化 ccs 和 irtc
               self.ccsClient = [[CCSClient alloc] init];
               self.irtcSDK = [[IRTCSDK alloc] init];
               self.irtcSDK.delegate = self.delegate;
               self.ccsClient.irtcSDK = self.irtcSDK;
               // 处理返回的数据
               self.zcoModelUserInfo = [[ZcoModelUserInfo alloc] initWithDictionary:[result.userInfo valueForKey:@"data"]];
               api.token = self.zcoModelUserInfo.accessToken;
               self.baseUrl = serviceUrl;
               // 登录成功后连接 CCS
               [self.ccsClient connectWithUrl:self.baseUrl andToken:api.token complete:^(CallBackObject * _Nonnull connectResult) {
                   if (connectResult.code == 200) {
                       self.ccsClient.ivcsSDKDelegate = self.delegate;
                       // 设置 ccs 消息的 delegate
                       AgentCcsClientMessageDelegate *messageDelegate = [[AgentCcsClientMessageDelegate alloc] init];
                       messageDelegate.ivcsAgentDelegate = self.delegate;
                       self.ccsClient.messageDelegate = messageDelegate;
                       // 设置 ams 的 delegate
                       [AmsClient sharedAms].delegate = self.delegate;
                       // 保存用户信息
                       self.ccsClient.userInfo = self.zcoModelUserInfo;
                       api.token = self.zcoModelUserInfo.accessToken;
                       api.baseUrl = self.baseUrl;
                       onSuccess(self.zcoModelUserInfo);
                   }else{
                       NSError *error = [[NSError alloc] initWithDomain:ivcsCcsErrorDomain code:3001 userInfo:@{@"message":@"amsClient未初始化"}];
                       onFailure(error);
                   }
               }];
           }else{
               onFailure([IvcsAgent sdkonFailureWithResponse:result]);
           }
       }];
}

- (void)loginWithUrl:(NSString *)baseUrl andToken:(NSString *)token complete:(completeBlock)complete{
    [[AmsClient sharedAms] connectWithUrl:baseUrl andToken:token complete:complete];
}

-(void)getBusinessScenariosByAgentName:(NSString *)agentName onSuccess:(void (^)(ZcoModelScenariosEnable * _Nonnull))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [[AgentApi sharedAgent] getBusinessScenariosByAgentName:agentName onSuccess:onSuccess onFailure:onFailure];
}

- (void)getBusinessScenarios:(void (^)(NSMutableArray<ZcoModelScenarioBrief *> * _Nonnull))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [[AgentApi sharedAgent] getBusinessScenarios:onSuccess onFailure:onFailure];
}

- (void)checkIn:(NSArray<NSNumber *> *)scenrioIds complete:(completeBlock)complete{
    [[AmsClient sharedAms] sendMessage:@"agent-checkIn" withData:@{
        @"groups":scenrioIds
    } complete:complete];
}

-(void)checkOut:(nonnull NSArray<NSNumber *> *) scenrioIds complete:(completeBlock)complete{
    [[AmsClient sharedAms] sendMessage:@"agent-checkOut" withData:@{
        @"groups":scenrioIds
    } complete:complete];
}

- (void)ready:(completeBlock)complete{
    [[AmsClient sharedAms] sendMessage:@"agent-ready" withData:nil complete:complete];
}

-(void)unready:(completeBlock)complete{
    [[AmsClient sharedAms] sendMessage:@"agent-unready" withData:nil complete:complete];
}
//agent-reject
-(void)getRelax:(NSDictionary *)dic complete:(completeBlock)complete{
    [[AmsClient sharedAms] sendMessage:@"agent-otherWork" withData:dic complete:complete];

}

-(void)shareScreenMethod{
    [[IRTCSDK shared]publishShareStreamToRoomWithStreamLabel:@"screen" mediaStreamSettingOptions:self.mediaOptions onSuccess:^(IRTCLocalCameraStream * _Nonnull localStream, IRTCConferencePublication * _Nonnull publication) {
            
        } onFailure:^(NSError * _Nonnull failure) {
            
        }];

}

- (void)answer:(IRTCCameraPreviewView *)view complete:(completeBlock)complete{
    [[AmsClient sharedAms] sendMessage:@"agent-answer" withData:nil complete:^(CallBackObject * _Nonnull callBackObject) {
        //FIXME: 这里会返回 Cannot read property 'invAgentChannel' of undefined ，如果忽略也能正常通话，为什么？
//        if (!callBackObject.success) {
//            complete(callBackObject);
//            return;
//        }
        NSString *invitationId = [AmsClient sharedAms].ringData.invitationId;
        NSString *sessionId = [AmsClient sharedAms].ringData.session.idField;
        NSLog(@"invitationId ======= %@ sessionId == %@",invitationId,sessionId);
        [[CCSClient shared] joinSession:invitationId withSessionId:sessionId onSuccess:^(NSDictionary * _Nonnull result) {
                MyLog(@"加入 session 成功：%@" , [IvcsAgent toJsonString:result]);
                self.sessionInfo = [[ZcoModelSessionInfo alloc] initWithDictionary:result];
                self.roomToken = self.sessionInfo.roomToken;
                self.roomId = self.sessionInfo.roomId;
                self.sessionId = self.sessionInfo.sessionId;
                self.clientId = self.sessionInfo.clientId;
                // ccs
                self.ccsClient.roomtoken = self.roomToken;
                self.ccsClient.sessionId = self.sessionId;
                self.ccsClient.clientId = self.clientId;
                [[IRTCSDK shared] joinRoomWithToken:self.roomToken onSuccess:^(IRTCConferenceInfo * _Nonnull info) {
                    MyLog(@"加入 room 成功!");
                    NSString *videoLabel;
                    for(ZcoModelMember *member in self.sessionInfo.members){
                        if ([member.idField isEqualToString: self.clientId]) {
                            videoLabel = [member getVideoLabel];
                            
                            break;
                        }else{
                            if ([member.role containsString:@"agent"]) {
                                [[NSNotificationCenter defaultCenter]postNotificationName:@"SessionNoti" object:@{@"session":member.idField}];
                            }
                        }
                    }
                    [[IRTCSDK shared] publishLocalStreamToRoomWithStreamLabel:videoLabel mediaStreamSettingOptions:self.mediaOptions onSuccess:^(IRTCLocalCameraStream * _Nonnull localStream, IRTCConferencePublication * _Nonnull publication) {
                        MyLog(@"推流成功!");
                        self.localStreamLabel = videoLabel;
                        if (view) {
                            [localStream attachCameraPreview:view];
                        }
                        self.localStream = localStream;
                        [[CCSClient shared] readyToTalkToRoles:agentCheckRole(nil) onSuccess:^{
                                  MyLog(@"通知系统坐席端已做好接通会话的准备");
                                CallBackObject *pubStreamSuccess =[[CallBackObject alloc] init];
                                pubStreamSuccess.message = videoLabel;
                                complete(pubStreamSuccess);
                            } onFailure:^(NSError * _Nonnull error) {
                                [self resError:error withCompleteBlock:complete];
                            }];
                    } onFailure:^(NSError * _Nonnull error) {
                        [self resError:error withCompleteBlock:complete];
                    }];
                } onFailure:^(NSError * _Nonnull error) {
                    [self resError:error withCompleteBlock:complete];
                }];
            } onFailure:^(NSError * _Nonnull error) {
                [self resError:error withCompleteBlock:complete];
            }];
    }];
}

/**
 将 NSError 转换成 completeBlock
 */
-(void)resError:(NSError * _Nonnull)error withCompleteBlock:(completeBlock)complete{
    CallBackObject *callBackObject = [[CallBackObject alloc] init];
    callBackObject.code = 0;
    callBackObject.message = error.description;
    complete(callBackObject);
}

-(void)quitSession:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    MyLog(@"irtc in ivcs 开始离开房间：%@" , self.irtcSDK);
    [self.irtcSDK leaveRoomSuccess:^{
        MyLog(@"irtc in ivcs 离开房间成功");
        
//        [[AmsClient sharedAms ]sendMessage:@"unpublish" withData:@{@"id":[NSNumber numberWithLong:arc4random() % 10000000000000],
//                } complete:^(CallBackObject * _Nonnull callBackObject) {
//            [[AmsClient sharedAms ]sendMessage:@"unsubscribe" withData:@{@"id":[NSNumber numberWithLong:arc4random() % 10000000000000],
//                    } complete:^(CallBackObject * _Nonnull callBackObject) {
//
//            }];
//        }];
        [[AmsClient sharedAms] sendMessage:@"logout" withData:nil complete:^(CallBackObject * _Nonnull callBackObject) {
           
        }];
        [CCSClient validateCcsClient:self.ccsClient onSuccess:^{
            NSLog(@"IVCSSDK: ivcs quit session success.");
            
            NSDictionary *dic = @{
                @"businessType":@"system_msg",
                @"message":@"agent end session",
                @"info": @{},
            };
            [self.ccsClient sendNormalSession:dic with:@"custom" to:@"customers" onSuccess:^{
                [self.ccsClient quitSession:@{} onSuccess:^{
                    onSuccess();
                } onFailure:^(NSError * _Nonnull error) {
                    onFailure(error);
                }];
            } onFailure:^(NSError * _Nonnull error) {
                onFailure(error);
            }];
           
        } onFailure:^(NSError * _Nonnull error) {
            NSLog(@"IVCSSDK: ivcs quit session failure.");
            onFailure(error);
        }];
    } onFailure:^(NSError * _Nonnull error) {
        MyLog(@"irtc in ivcs 离开房间失败:%@" , error);
        onFailure(error);
    }];
}

-(void)sendTextMessage:(NSString *)data toRoles:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [CCSClient validateCcsClient:self.ccsClient onSuccess:^{
        [self.ccsClient sendTextMessage:data toRoles:agentCheckRole(roles) onSuccess:^{
            onSuccess();
        } onFailure:^(NSError * _Nonnull error) {
            onFailure(error);
        }];
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}
-(void)sendCustomMessage:(id)data toRoles:(NSString *__nullable)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [CCSClient validateCcsClient:self.ccsClient onSuccess:^{
        [self.ccsClient sendCustomMessage:data toRoles:agentCheckRole(roles) onSuccess:^{
            if(onSuccess){
                onSuccess();
            }
        } onFailure:^(NSError * _Nonnull error) {
            if (onFailure) {
                onFailure(error);
            }
        }];
    } onFailure:^(NSError * _Nonnull error) {
        if (onFailure) {
            onFailure(error);
        }
    }];
}

-(void)shareResourceWithType:(NSString *)type resourceUrl:(NSString *)url resourceName:(NSString *)name toRoles:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [CCSClient validateCcsClient:self.ccsClient onSuccess:^{
        [self.ccsClient shareResourceWithType:type resourceUrl:url resourceName:name toRoles:roles onSuccess:^{
            onSuccess();
        } onFailure:^(NSError * _Nonnull error) {
            onFailure(error);
        }];
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}

-(void)shareResourceWithType:(NSString *)type uploadUrl:(NSString *)uploadUrl fileData:(NSData *)fileData fileName:(NSString *)fileName mimeType:(NSString *)mimeType toRoles:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [CCSClient validateCcsClient:self.ccsClient onSuccess:^{
        [self.ccsClient shareResourceWithType:type uploadUrl:uploadUrl fileData:fileData fileName:fileName mimeType:mimeType toRoles:roles onSuccess:^{
            onSuccess();
        } onFailure:^(NSError * _Nonnull error) {
            onFailure(error);
        }];
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}
- (void)sendPeerResponse:(ZcoModelCMD *)cmd to:(NSString *)roles onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [CCSClient validateCcsClient:self.ccsClient onSuccess:^{
        [self.ccsClient sendPeerResponse:cmd to:agentCheckRole(roles) onSuccess:onSuccess onFailure:onFailure];
        } onFailure:^(NSError * _Nonnull error) {
            if (onFailure) {
                onFailure(error);
            }
        }];
}

-(void)renderStreamWithLabel:(NSString *)label renderView:(NSObject<IRTCVideoRenderer>*)renderer onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    IRTCRemoteStream *stream = [self.labelAndStreams valueForKey:label];
    [self.irtcSDK subscribeStreamWithLabel:label IRTCRemoteStream:stream onSuccess:^(IRTCConferenceSubscription * _Nonnull subscription) {
        [stream attach:renderer];
        dispatch_async(dispatch_get_main_queue(), ^{
            onSuccess();
        });
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}

-(void)renderStreamWithStream:(IRTCRemoteStream *)stream AndLabel:(NSString *)label renderView:(NSObject<IRTCVideoRenderer>*)renderer onSuccess:(void (^)(void))onSuccess onFailure:(void (^)(NSError * _Nonnull))onFailure{
    [self.irtcSDK subscribeStreamWithLabel:label IRTCRemoteStream:stream onSuccess:^(IRTCConferenceSubscription * _Nonnull subscription) {
        NSLog(@"currentStream====%@",stream);
        [stream attach:renderer];
        NSLog(@"streamInfo ====%@,%@,render====%@",stream.streamId,stream.origin,renderer);
        dispatch_async(dispatch_get_main_queue(), ^{
            onSuccess();
        });
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}
-(void)getSnapShotImage:(void (^)(UIImage*))onSuccess onFailure:(void (^)(NSError*))onFailure{
    [self.irtcSDK getCustomerSnapShotImage:^(UIImage * _Nonnull image) {
        onSuccess(image);
    } onFailure:^(NSError * _Nonnull error) {
        onFailure(error);
    }];
}

- (void)acceptHandWritingMessage:(NSString * _Nullable)msg to:(NSString * _Nullable)roles{
    [CCSClient validateCcsClient:self.ccsClient onSuccess:^{
        if (msg == nil) {
            [self.ccsClient sendHandWritingMessage:@"{\"version\":\"3.4.0\",\"objects\":[]}" to:agentCheckRole(roles)];
        }else{
            [self.ccsClient sendHandWritingMessage:msg to:agentCheckRole(roles)];
        }
            
        } onFailure:^(NSError * _Nonnull error) {
            NSLog(@"sendHandWritingMessage failed: %@" , error);
            onFailure(error);
        }];
}

- (void)attachStreamWithLabel:(NSString *)label renderView:(NSObject<IRTCVideoRenderer> *)view{
    if ([self.localStreamLabel isEqualToString:label]) {
        [self.localStream attach:view];
        return;
    }
    IRTCStream *stream = [self.labelAndStreams valueForKey:label];
    [stream attach:view];
}

+(NSError *)sdkonFailureWithResponse:(CallBackObject *)result{
    NSError *error = [[NSError alloc] initWithDomain:ivcsAgentSDKErrorDomain code:result.code userInfo:result.userInfo];
    return error;
}

+(NSString *)toJsonString:(id)data{
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:data options:NSJSONWritingPrettyPrinted error:&error];
    NSString *jsonString;
    if (!jsonData) {
        MyLog(@"%@",error);
    } else {
        jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
    }
    NSMutableString *mutStr = [NSMutableString stringWithString:jsonString];
    NSRange range = {0,jsonString.length};
    //去掉字符串中的空格
    [mutStr replaceOccurrencesOfString:@" " withString:@"" options:NSLiteralSearch range:range];
    NSRange range2 = {0,mutStr.length};
    //去掉字符串中的换行符
    [mutStr replaceOccurrencesOfString:@"\n" withString:@"" options:NSLiteralSearch range:range2];
    return mutStr;
}
@end
